home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************
- Project : MacPerl - Real Perl Application
- File : MPCGI.c - CGI Scripts for MacHTTP
- Author : Matthias Neeracher
- Language : MPW C
-
- $Log: MPCGI.c,v $
- Revision 1.1 1994/07/30 23:28:34 neeri
- Initial revision
-
- *********************************************************************/
-
- #include <Dialogs.h>
- #include <QuickDraw.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <Fonts.h>
- #include <AppleEvents.h>
- #include <AERegistry.h>
- #include <Processes.h>
- #include <files.h>
- #include <StandardFile.h>
- #include <Aliases.h>
- #include <GestaltEqu.h>
- #include <Folders.h>
- #include <Errors.h>
- #include <Resources.h>
- #include <TextUtils.h>
- #include <SegLoad.h>
- #include <LowMem.h>
-
- #if !defined(powerc) && !defined(__powerc)
- #pragma segment Main
- #endif
-
- #define FAILOSERR(call) if (err = call) return err; else 0
-
- #define kWWWEventClass 'WWWΩ'
- #define kWWWSearch 'srch'
- #define kWWWSearchDoc 'sdoc'
-
- typedef struct {
- AEKeyword key;
- char * text;
- } ArgDesc;
-
- #define kForKeyword 'kfor' /* search args */
- #define kUserKeyword 'user' /* authenticated user name */
- #define kPasswordKeyword 'pass' /* authenticated password */
- #define kFromUser 'frmu' /* "from:" username in HTTP header */
- #define kAddressKeyword 'addr' /* remote client address */
- #define kPostKeyword 'post' /* arguments passed via POST */
- #define kMethodKeyword 'meth' /* which method? GET, POST, HEAD */
- #define kServerName 'svnm' /* address of the local server */
- #define kServerPort 'svpt' /* port of the local server */
- #define kScriptName 'scnm' /* URL path to the running script */
- #define kContentType 'ctyp' /* type of data in POST args */
- #define kRefererKeyword 'refr' /* Page that pointed to this URL */
- #define kUserAgentKeyword 'Agnt' /* name of client software */
-
- ArgDesc gArguments[] =
- {
- {keyDirectObject, "-path=" },
- {kForKeyword, "-search=" },
- {kUserKeyword, "-user=" },
- {kPasswordKeyword, "-password=" },
- {kFromUser, "-from=" },
- {kAddressKeyword, "-address=" },
- {kPostKeyword, "-post=" },
- {kMethodKeyword, "-method=" },
- {kServerName, "-server-name=" },
- {kServerPort, "-server-port=" },
- {kScriptName, "-script-name=" },
- {kContentType, "-content-type=" },
- {kRefererKeyword, "-referer=" },
- {kUserAgentKeyword, "-user-agent=" },
- {0, 0}
- };
-
- const char * gDiagPrefix = "\n<H1>Diagnostic Output</H1>\n<PRE>\n";
- const char * gDiagSuffix = "\n</PRE>\n";
-
- #define TIMEOUT 5*60*60 /* Wait up to 5 minutes */
-
- AliasHandle gMySelf;
- EventRecord gLastEvent;
- long gLastTicks;
- DialogPtr gInfoDlg;
- Boolean gTime2Go = false;
-
- pascal Boolean WeAreInFront()
- {
- ProcessSerialNumber we;
- ProcessSerialNumber front;
- Boolean same;
-
- return !GetCurrentProcess(&we)
- && !GetFrontProcess(&front)
- && !SameProcess(&we, &front, &same)
- && same;
- }
-
- pascal Boolean CheckEnvironment()
- {
- long result;
-
- if (Gestalt(gestaltAppleEventsAttr, &result))
- return false;
-
- return (result & (1 << gestaltAppleEventsPresent)) != 0;
- } /* CheckEnvironment */
-
- /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
-
- OSErr MacPerlRunning(ProcessSerialNumber *psn)
- {
- OSErr err;
- ProcessInfoRec info;
-
- psn->highLongOfPSN = 0;
- psn->lowLongOfPSN = kNoProcess;
- do {
- FAILOSERR(GetNextProcess(psn));
-
- info.processInfoLength = sizeof(info);
- info.processName = nil;
- info.processAppSpec = nil;
-
- FAILOSERR(GetProcessInformation(psn, &info));
- } while(info.processSignature != 'McPL');
-
- *psn = info.processNumber;
-
- return noErr;
- }
-
- OSErr GetSysVolume(short *vRefNum)
- {
- long dir;
-
- return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
- }
-
- OSErr GetIndVolume(short index, short *vRefNum)
- {
- OSErr err;
- ParamBlockRec pb;
-
- pb.volumeParam.ioNamePtr = nil;
- pb.volumeParam.ioVolIndex = index;
-
- FAILOSERR(PBGetVInfoSync(&pb));
-
- *vRefNum = pb.volumeParam.ioVRefNum;
-
- return noErr;
- }
-
- OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
- {
- OSErr err;
- HParamBlockRec pb;
- GetVolParmsInfoBuffer info;
-
- pb.ioParam.ioNamePtr = nil;
- pb.ioParam.ioVRefNum = vRefNum;
- pb.ioParam.ioBuffer = (Ptr)&info;
- pb.ioParam.ioReqCount = sizeof(GetVolParmsInfoBuffer);
-
- FAILOSERR(PBHGetVolParmsSync(&pb));
-
- *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
-
- return noErr;
- }
-
- OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
- {
- OSErr err;
- DTPBRec pb;
-
- /* Get Acess path to Desktop database on this volume */
-
- pb.ioVRefNum = vRefNum;
- pb.ioNamePtr = nil;
- FAILOSERR(PBDTGetPath(&pb));
-
- pb.ioIndex = 0;
- pb.ioFileCreator = 'McPL';
- pb.ioNamePtr = file->name;
- switch (err = PBDTGetAPPLSync(&pb)) {
- case noErr:
- file->vRefNum = vRefNum;
- file->parID = pb.ioAPPLParID;
-
- return noErr;
- case fnfErr:
- return afpItemNotFound; /* Bug in PBDTGetAPPL */
- default:
- return err;
- }
- }
-
- OSErr LaunchIt(FSSpecPtr fileSpec, ProcessSerialNumber * psn )
- {
- OSErr err;
- LaunchParamBlockRec pb;
-
- pb.launchBlockID = extendedBlock;
- pb.launchEPBLength = extendedBlockLen;
- pb.launchFileFlags = launchNoFileFlags;
- pb.launchControlFlags = launchContinue + launchNoFileFlags;
- pb.launchAppSpec = fileSpec;
- pb.launchAppParameters = nil;
-
- FAILOSERR(LaunchApplication(&pb));
-
- *psn = pb.launchProcessSN;
-
- return noErr;
- }
-
- /* Get the psn ofa copy of MacPerl. Launch one if necessary. Buy one. Steal one. */
- static OSErr LaunchMacPerl(ProcessSerialNumber *psn)
- {
- OSErr err;
- short vRefNum, sysVRefNum, index;
- FSSpec file;
- Boolean hasDesktopDB;
-
- /* See if ToolServer is already running: */
- err = MacPerlRunning(psn);
-
- if (err != procNotFound)
- return err;
-
- /* Not running, try to launch it */
-
- FAILOSERR(GetSysVolume(&sysVRefNum));
-
- vRefNum = sysVRefNum;
-
- for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
- if (!index || vRefNum != sysVRefNum) {
- if (err = VolHasDesktopDB(vRefNum,&hasDesktopDB))
- return err;
-
- if (hasDesktopDB)
- switch (err = FindAppOnVolume(vRefNum, &file)) {
- case noErr:
- return LaunchIt(&file, psn);
- case afpItemNotFound:
- break;
- default:
- return err;
- }
- }
- }
-
- switch (err) {
- case nsvErr:
- case afpItemNotFound:
- return fnfErr;
- default:
- return err;
- }
- }
-
- void WhoAmI(AliasHandle * self)
- {
- FSSpec me;
- FCBPBRec fcb;
-
- fcb.ioNamePtr = &me.name;
- fcb.ioRefNum = CurResFile();
- fcb.ioFCBIndx = 0;
-
- PBGetFCBInfoSync(&fcb);
-
- me.vRefNum = fcb.ioFCBVRefNum;
- me.parID = fcb.ioFCBParID;
-
- NewAlias(nil, &me, self);
- }
-
- pascal OSErr Ignore(const AppleEvent *message, AppleEvent *reply, long refcon)
- {
- return noErr;
- }
-
- pascal OSErr DoSearch(const AppleEvent *message, AppleEvent *reply, long refcon)
- {
- OSErr err;
- AppleEvent doscript;
- AppleEvent perlSez;
- ProcessSerialNumber perl;
- AEAddressDesc perladdr;
- AEDescList searchArgs;
- AEDesc arg;
- AEDesc outp;
- AEDesc diag;
- Boolean doDebug = true;
-
- switch (err = LaunchMacPerl(&perl)) {
- case noErr:
- break;
- case fnfErr:
- ParamText(
- (StringPtr) "\pFailed to launch MacPerl. Either you don't have MacPerl "
- "or your desktop needs to be rebuilt.", (StringPtr) "\p", "\p", "\p");
- Alert(4096, nil);
-
- return err;
- default:
- ParamText(
- (StringPtr) "\pFailed to launch MacPerl (possibly because of "
- "a memory problem).", (StringPtr) "\p", "\p", "\p");
- Alert(4096, nil);
-
- return err;
- }
-
- FAILOSERR(
- AECreateDesc(
- typeProcessSerialNumber,
- (Ptr)&perl,
- sizeof(ProcessSerialNumber),
- &perladdr));
-
- FAILOSERR(
- AECreateAppleEvent(
- kAEMiscStandards, kAEDoScript, &perladdr,
- kAutoGenerateReturnID, kAnyTransactionID,
- &doscript));
-
- FAILOSERR(AECreateList(nil,0,false,&searchArgs));
-
- HLock((Handle) gMySelf);
- FAILOSERR(AEPutPtr(&searchArgs, 0, typeAlias, (Ptr) *gMySelf, GetHandleSize((Handle) gMySelf)));
- HUnlock((Handle) gMySelf);
-
- if (refcon) {
- int argument;
-
- for (argument=0; gArguments[argument].key; ++argument)
- if (!AEGetParamDesc(message, gArguments[argument].key, typeChar, &arg)) {
- Munger(
- arg.dataHandle, 0, nil, 0,
- gArguments[argument].text, strlen(gArguments[argument].text));
- FAILOSERR(AEPutDesc(&searchArgs, 0, &arg));
- AEDisposeDesc(&arg);
- }
- } else {
- if (!AEGetParamDesc(message, keyDirectObject, typeChar, &arg)) {
- Munger(arg.dataHandle, 0, nil, 0, "-search=", 8);
- FAILOSERR(AEPutDesc(&searchArgs, 0, &arg));
- AEDisposeDesc(&arg);
- }
- }
-
- FAILOSERR(AEPutParamDesc(&doscript, keyDirectObject, &searchArgs));
- FAILOSERR(AEPutParamPtr(&doscript, 'MODE', typeEnumerated, "BATC", 4));
- FAILOSERR(
- AESend(
- &doscript, &perlSez,
- kAEWaitReply+kAENeverInteract,
- kAENormalPriority, kAEDefaultTimeout,
- nil, nil));
-
- FAILOSERR(AEGetParamDesc(&perlSez, keyDirectObject, typeWildCard, &arg));
-
- if (!AEGetParamDesc(&perlSez, 'OUTP', typeWildCard, &outp)) {
- if (!AEGetKeyDesc(&outp, 'diag', typeWildCard, &diag)) {
- PtrAndHand(gDiagPrefix, arg.dataHandle, strlen(gDiagPrefix));
- HandAndHand(diag.dataHandle, arg.dataHandle);
- PtrAndHand(gDiagSuffix, arg.dataHandle, strlen(gDiagSuffix));
-
- AEDisposeDesc(&diag);
- }
- AEDisposeDesc(&outp);
- }
-
- FAILOSERR(AEPutParamDesc(reply, keyDirectObject, &arg));
-
- AEDisposeDesc(&arg);
- AEDisposeDesc(&perlSez);
-
- return noErr;
- }
-
- pascal void MainEvent(void)
- {
- DialogPtr myDialog;
- short myItemHit;
-
- if (WaitNextEvent(everyEvent, &gLastEvent, 60*60, nil))
- switch (gLastEvent.what) {
- case keyDown:
- case autoKey:
- switch (gLastEvent.message & charCodeMask) {
- case 'Q':
- case '.':
- if ((gLastEvent.modifiers & cmdKey) != cmdKey)
- break;
- /* Else fall through */
- case 13: /* Return */
- case 3: /* Enter */
- case 27: /* ESC */
- gTime2Go = true;
- return;
- }
- SysBeep(0);
- break;
- case kHighLevelEvent:
- AEProcessAppleEvent(&gLastEvent);
- gLastTicks = TickCount();
- break;
- case osEvt:
- switch (gLastEvent.message & osEvtMessageMask) { /*high byte of message*/
- case 0x01000000:
- if (gLastEvent.message & resumeFlag)
- ShowWindow(gInfoDlg);
- else
- ShowWindow(gInfoDlg);
- }
- break;
- default:
- gTime2Go = DialogSelect(&gLastEvent, &myDialog, &myItemHit);
- break;
- }
- }
-
- void main()
- {
- InitGraf(&qd.thePort);
- InitFonts();
- FlushEvents(everyEvent, 0);
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- /*check environment checks to see if we are running 7.0*/
- if (!CheckEnvironment()) {
- SetCursor(&qd.arrow);
- /*pose the only 7.0 alert*/
- ParamText(
- (StringPtr) "\pMacHTTP CGI scripts need at least System 7.0 to run.",
- (StringPtr) "\p", "\p", "\p");
- Alert(4096, nil);
-
- ExitToShell();
- }
-
- /* This code will not go native anytime soon */
- AEInstallEventHandler( kCoreEventClass, kAEOpenApplication, (AEEventHandlerUPP)Ignore, 0, false) ;
- AEInstallEventHandler( kWWWEventClass, kWWWSearch, (AEEventHandlerUPP)DoSearch, 0, false ) ;
- AEInstallEventHandler( kWWWEventClass, kWWWSearchDoc, (AEEventHandlerUPP)DoSearch, 1, false ) ;
-
- WhoAmI(&gMySelf);
-
- gInfoDlg = GetNewDialog(4097, nil, (WindowPtr) -1);
- SetWTitle(gInfoDlg, LMGetCurApName());
-
- if (WeAreInFront())
- ShowWindow(gInfoDlg);
-
- for (gLastTicks = TickCount(); !gTime2Go && (TickCount() - gLastTicks < TIMEOUT); )
- MainEvent();
- }
-